﻿Public Class NFAConverter
    Inherits RegularExpressionConverter(Of NFAModel)

    Private Class InstanceHolder
        Friend Shared s_Instance As NFAConverter = New NFAConverter
    End Class

    Public Shared ReadOnly Property [Default] As NFAConverter
        Get
            Return InstanceHolder.s_Instance
        End Get
    End Property

    Protected Overrides Function ConvertAlternation(ByVal expression As Alternation) As NFAModel
        Dim leftNFA = Convert(expression.Left)
        Dim rightNFA = Convert(expression.Right)

        Dim newHead As New NFAState
        Dim newTail As New NFAState

        'build edges
        newHead.AddEdge(leftNFA.EntryEdge)
        newHead.AddEdge(rightNFA.EntryEdge)

        leftNFA.TailState.AddEdge(newTail)
        rightNFA.TailState.AddEdge(newTail)

        Dim alternationNFA As New NFAModel()

        With alternationNFA
            .AddState(newHead)
            .AddStates(leftNFA.States)
            .AddStates(rightNFA.States)
            .AddState(newTail)

            'an empty entry edge
            .EntryEdge = New NFAEdge(newHead)
            .TailState = newTail
        End With

        Return alternationNFA
    End Function

    Protected Overrides Function ConvertConcatenation(ByVal expression As Concatenation) As NFAModel
        Dim leftNFA = Convert(expression.Left)
        Dim rightNFA = Convert(expression.Right)

        'connect left with right
        leftNFA.TailState.AddEdge(rightNFA.EntryEdge)

        Dim concatenationNFA As New NFAModel

        With concatenationNFA
            .AddStates(leftNFA.States)
            .AddStates(rightNFA.States)
            .EntryEdge = leftNFA.EntryEdge
            .TailState = rightNFA.TailState
        End With

        Return concatenationNFA
    End Function

    Protected Overrides Function ConvertEmpty(ByVal expression As Empty) As NFAModel
        Dim newTail As New NFAState
        Dim entry As New NFAEdge(newTail)

        Dim emptyNFA As New NFAModel

        With emptyNFA
            .AddState(newTail)
            .TailState = newTail
            .EntryEdge = entry
        End With

        Return emptyNFA
    End Function

    Protected Overrides Function ConvertKleeneStar(ByVal expression As KleeneStar) As NFAModel
        Dim innerNFA = Convert(expression.InnerExpression)

        Dim newTail As New NFAState
        Dim entry As New NFAEdge(newTail)

        innerNFA.TailState.AddEdge(newTail)
        newTail.AddEdge(innerNFA.EntryEdge)

        Dim kleenStarNFA As New NFAModel

        With kleenStarNFA
            .AddStates(innerNFA.States)
            .AddState(newTail)
            .EntryEdge = entry
            .TailState = newTail
        End With

        Return kleenStarNFA
    End Function

    Protected Overrides Function ConvertLiteralChar(ByVal expression As LiteralChar) As NFAModel
        Dim newTail As New NFAState
        Dim entry As New NFAEdge(expression.Value, newTail)

        Dim literalCharNFA As New NFAModel

        With literalCharNFA
            .AddState(newTail)
            .TailState = newTail
            .EntryEdge = entry
        End With

        Return literalCharNFA
    End Function

    Protected Overrides Function ConvertLiteralRange(ByVal expression As LiteralRange) As NFAModel
        Dim newTail As New NFAState
        Dim entry As New NFAEdge(expression.Range, newTail)

        Dim literalRangeNFA As New NFAModel

        With literalRangeNFA
            .AddState(newTail)
            .TailState = newTail
            .EntryEdge = entry
        End With

        Return literalRangeNFA
    End Function
End Class
